/* 
*  Copyright (C) 2009-2010 WCG Project
*
*  This program is free software; you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by the
*  Free Software Foundation; either version 2 of the License, or (at
*  your option) any later version.
*
*  This program is distributed in the hope that it will be useful, but
*  WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software Foundation,
*  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*  In addition, as a special exception, the author gives permission to
*  link the code of this program with the Half-Life Game Engine ("HL
*  Engine") and Modified Game Libraries ("MODs") developed by Valve,
*  L.L.C ("Valve"). You must obey the GNU General Public License in all
*  respects for all of the code used other than the HL Engine and MODs
*  from Valve. If you modify this file, you may extend this exception
*  to your version of the file, but you are not obligated to do so. If
*  you do not wish to do so, delete this exception statement from your
*  version.
*/



new const Float:p_arcaneshot[5]			= {0.06, 0.12, 0.18, 0.24, 0.30}
new const Float:p_wingclip[5]			= {0.04, 0.08, 0.12, 0.16, 0.20}
new const p_serpent[5]					= {12, 14, 16, 18, 20}
new const Float:p_serpentsting[5] 		= {0.04, 0.08, 0.12, 0.16, 0.20}
new const Float:p_beastwithin[5] 		= {1.08, 1.11, 1.14, 1.17, 1.20}


HUNTER_InitSkills()
{
	SM_InitSkill( SKILL_ARCANESHOT, CLASS_HUNTER, SKILL_TYPE_TRAINABLE, sizeof(p_arcaneshot), 1, 3 )
	SM_InitSkill( SKILL_WINGCLIP, CLASS_HUNTER, SKILL_TYPE_TRAINABLE, sizeof(p_wingclip), 1, 3 )
	SM_InitSkill( SKILL_SERPENTSTING, CLASS_HUNTER, SKILL_TYPE_TRAINABLE, sizeof(p_serpentsting), 10, 3 )
	SM_InitSkill( ABILITY_SERPENTWARD, CLASS_HUNTER, SKILL_TYPE_ABILITY, sizeof(p_serpent) )
	SM_InitSkill( ULTIMATE_BEASTWITHIN, CLASS_HUNTER, SKILL_TYPE_ULTIMATE, 5, 10, 30 )
}



//-----------------------------------------
// HUNTER_TriggerAbility
//
//-----------------------------------------
HUNTER_TriggerAbility( id, iSkillID )
{
	if( iSkillID == ABILITY_SERPENTWARD )
	{
		new iSkillLevel = SM_GetSkillLevel( id, ABILITY_SERPENTWARD )
		new iMaxNumWards = floatround(float(iSkillLevel) / 2.0, floatround_ceil)

		if( GameInfo[GI_EndRound] == true )
		{
			WCG_StatusText( id, 0, HUD_AUTO, "Round is over, can not place serpent wards" )
			return
		}
		else if( PlayerInfo[id][PI_SerpentCount] >= iMaxNumWards )
		{
			WCG_StatusText( id, 0, HUD_AUTO, "You have already placed all your wards" )
			return
		}
		else if( !HUNTER_CanPlaceWard( id ) )
		{
			WCG_StatusText( id, 0, HUD_AUTO, "You cannot place a serpent ward here" )
			return
		}

		new param[1]
		param[0] = id
		PLAYER_CastSpell( id, ABILITY_SERPENTWARD, CAST_NORMAL, "_SPELL_PlaceSerpentWard", param, 1 )
	}
}



//------------------------------------
// HUNTER_TriggerUltimate
//
//------------------------------------
HUNTER_TriggerUltimate( id, iSkillID )
{
	if( iSkillID == ULTIMATE_BEASTWITHIN )
	{
		new param[1]
		param[0] = id
		PLAYER_CastSpell( id, ULTIMATE_BEASTWITHIN, CAST_NORMAL, "_SPELL_BeastWithin", param, 1 )
	}
}






//------------------------------------
// HUNTER_SkillsOffensive
//
//------------------------------------
public HUNTER_SkillsOffensive( iAttacker, iVictim, iWeapon, &iDamage, iDamageType )
{
	static iSkillLevel

	if( PlayerBuffInfo[iAttacker][BUFF_BeastWithin] == true )
	{
		if( iDamageType & (DMG_BULLET|DMG_SLASH) )
		{
			iSkillLevel = SM_GetSkillLevel( iAttacker, ULTIMATE_BEASTWITHIN )
			iDamage = floatround( float(iDamage) * p_beastwithin[iSkillLevel-1] )
		}
	}

	// Wingclip
	iSkillLevel = SM_GetSkillLevel( iAttacker, SKILL_WINGCLIP )
	if( iSkillLevel > 0 && (iDamageType & (DMG_BULLET|DMG_SLASH) ) && !PlayerInfo[iVictim][PI_Slowed] && !SM_IsOnCooldown( iAttacker, SKILL_WINGCLIP ))
	{
		if( random_float( 0.0, 1.0 ) <= p_wingclip[iSkillLevel-1] )
		{
			new param[2]
			param[0] = iVictim
			PLAYER_CastSpell( iAttacker, SKILL_WINGCLIP, CAST_PASSIVE, "_SPELL_Wingclip", param, 1 )
			return
		}
	}


	// Serpent Sting
	iSkillLevel = SM_GetSkillLevel( iAttacker, SKILL_SERPENTSTING )
	if( iSkillLevel > 0 && (iDamageType & (DMG_BULLET|DMG_SLASH)) && !SM_IsOnCooldown( iAttacker, SKILL_SERPENTSTING ) )
	{
		if( random_float( 0.0, 1.0 ) <= p_serpentsting[iSkillLevel-1] )
		{
			new param[2]
			param[0] = iAttacker
			param[1] = iVictim
			PLAYER_CastSpell( iAttacker, SKILL_SERPENTSTING, CAST_PASSIVE, "_SPELL_SerpentSting", param, 2 )
			return
		}
	}

	// Arcane Shot
	iSkillLevel = SM_GetSkillLevel( iAttacker, SKILL_ARCANESHOT )
	if( iSkillLevel > 0 && (iDamageType & (DMG_BULLET|DMG_SLASH)) && !SM_IsOnCooldown( iAttacker, SKILL_ARCANESHOT ) )
	{
		if( random_float( 0.0, 1.0 ) <= p_arcaneshot[iSkillLevel-1] )
		{
			new param[2]
			param[0] = iAttacker
			param[1] = iVictim
			PLAYER_CastSpell( iAttacker, SKILL_ARCANESHOT, CAST_PASSIVE, "_SPELL_ArcaneShot", param, 2 )
			return
		}
	}


}


//------------------------------------
// HUNTER_SkillsDefensive
//
//------------------------------------
public HUNTER_SkillsDefensive( iAttacker, iVictim, &iDamage, iWeapon, iDamageType )
{
}






//--------------------------------------------------------------------------------------------------------------------------
// Wing Clip

//------------------------------------
// _SPELL_Wingclip
//
// PLAYER_CastSpell callback
//		param[0] = Victim ID
//------------------------------------
public _SPELL_Wingclip( const param[] )
{
	new iVictim = param[0]
	
	// We need to identify the victim as slowed
	PlayerInfo[iVictim][PI_Slowed] = get_pcvar_num( CVAR_frost )
		
	// Slow the user's speed
	PLAYER_UpdateSpeed( iVictim )

	// Set the user's gravity
	PLAYER_UpdateGravity( iVictim )

	// Set the user's rendering
	PLAYER_UpdateInvisibility( iVictim )

	set_task( 2.0, "SHARED_ResetMaxSpeed", TASK_RESETSPEED + iVictim )

	emit_sound( iVictim, CHAN_STATIC, g_szSounds[SOUND_WINGCLIP], VOL_NORM, ATTN_NORM, 0, PITCH_NORM )

	// Make the user glow!
	SHARED_Glow( iVictim, COLOR_RGB( 150, 150, 150 ) )

	// Lets create a screen fade
	EFFECT_ScreenFade( iVictim, 0.25, 0.25, COLOR_RGBA(255, 255, 255, 75) )
}


//--------------------------------------------------------------------------------------------------------------------------
// Serpent Sting


//------------------------------------
// _SPELL_SerpentSting
//
// PLAYER_CastSpell callback
//		param[0] = Attacker ID
//		param[1] = Victim ID
//------------------------------------
public _SPELL_SerpentSting( const param[2] )
{
	new iAttacker = param[0]
	new iVictim = param[1]
	
	static vOrigin[3], vTargetOrigin[3]
	
	get_user_origin( iAttacker, vOrigin )
	get_user_origin( iVictim, vTargetOrigin )
	
	Create_TE_SPRITETRAIL( vOrigin, vTargetOrigin, g_spr_xspark2, 40, 0, 2, 5, 5 )

	new param[3]
	param[0] = iAttacker
	param[1] = iVictim
	param[2] = 5
	_SerpentSting_Dot( param )

	emit_sound( iVictim, CHAN_STATIC, g_szSounds[SOUND_SERPENTSTING], VOL_NORM, ATTN_NORM, 0, PITCH_NORM )
}

//------------------------------------
// _SerpentSting_Dot
//
//------------------------------------
public _SerpentSting_Dot( param[] )
{
	new iAttacker	= param[0]
	new iVictim		= param[1]
	new iCount		= param[2]

	PLAYER_MagicDamage( iVictim, iAttacker, 8, CSW_SERPENTSTING )

	iCount--
	if( iCount < 0 )
		return

	param[2] = iCount
	
	set_task( 2.0, "_SerpentSting_Dot", TASK_ALIVE_EFFECT + iVictim, param, 3 )
}



//--------------------------------------------------------------------------------------------------------------------------
// Arcane Shot


//------------------------------------
// _SPELL_ArcaneShot
//
// PLAYER_CastSpell callback
//		param[0] = Attacker ID
//		param[1] = Victim ID
//------------------------------------
public _SPELL_ArcaneShot( const param[2] )
{
	new iAttacker = param[0]
	new iVictim = param[1]
	
	static vOrigin[3], vTargetOrigin[3]
	
	get_user_origin( iAttacker, vOrigin )
	get_user_origin( iVictim, vTargetOrigin )
	
	Create_TE_SPRITETRAIL( vOrigin, vTargetOrigin, g_spr_blueflare2, 40, 0, 2, 5, 5 )

	emit_sound( iVictim, CHAN_STATIC, g_szSounds[SOUND_ARCANEMISSILE], VOL_NORM, ATTN_NORM, 0, PITCH_NORM )
	PLAYER_MagicDamage( iVictim, iAttacker, 15, CSW_ARCANESHOT )
}






//--------------------------------------------------------------------------------------------------------------------------
// SerpentWard


//------------------------------------
// _SPELL_PlaceSerpentWard
//
// PLAYER_CastSpell callback
//		param[0] = Caster ID
//------------------------------------
public _SPELL_PlaceSerpentWard( param[] )
{
	new id = param[0]

	static args[9], Float:vStart[3], Float:vEnd[3]

	pev( id, pev_origin, vStart )

	// NOTE: Startpoint must be lower then the endpoint
	vEnd[0] = vStart[0]
	vEnd[1] = vStart[1]
	vEnd[2] = vStart[2] - 600
	engfunc( EngFunc_TraceLine, vStart, vEnd, IGNORE_MONSTERS|IGNORE_GLASS, FM_NULLENT, 0 )
	get_tr2( 0, TR_vecEndPos, vStart )
	
	vEnd[2] = vStart[2] + 600
	engfunc( EngFunc_TraceLine, vStart, vEnd, IGNORE_MONSTERS|IGNORE_GLASS, FM_NULLENT, 0 )
	get_tr2( 0, TR_vecEndPos, vEnd )

	args[0] = id
	args[1] = PlayerInfo[id][PI_TeamID]
	args[2] = (PlayerInfo[id][PI_TeamID] == TEAM_T) ? COLOR_RGBA(255,0,0,128) : COLOR_RGBA(0,0,255,128)
	args[3] = floatround( vStart[0] )
	args[4] = floatround( vStart[1] )
	args[5] = floatround( vStart[2] )
	args[6] = floatround( vEnd[0] )
	args[7] = floatround( vEnd[1] )
	args[8] = floatround( vEnd[2] )

	PlayerInfo[id][PI_SerpentCount]++
	GameInfo[GI_SerpentCount]++

	_HUNTER_DrawSerpentWard( args )

	new iSkillLevel = SM_GetSkillLevel( id, ABILITY_SERPENTWARD )
	new iMaxNumWards = floatround(float(iSkillLevel) / 2.0, floatround_ceil)

	WCG_StatusText( id, 0, HUD_AUTO, "%L", id, "SERPENT_WARD", iMaxNumWards - PlayerInfo[id][PI_SerpentCount] )
}



//------------------------------------
// _HUNTER_DrawSerpentWard
//
//------------------------------------
public _HUNTER_DrawSerpentWard( param[9] )
{
	static vStart[3], vEnd[3]

	new id = param[0]
	new team = param[1]
	new color = param[2]

	new bool:bRemoveMe = false
	
	if( !is_user_alive(id) )
		bRemoveMe = true

	else if( PlayerInfo[id][PI_SerpentCount] == 0 )
		bRemoveMe = true

	else if( PlayerInfo[id][PI_TeamID] != team )
		bRemoveMe = true

	else if( PlayerInfo[id][PI_KillAllWards] == true )
		bRemoveMe = true

	else if( GameInfo[GI_EndRound] == true )
		bRemoveMe = true

	
	if( bRemoveMe == true )
	{
		PlayerInfo[id][PI_SerpentCount] = max( --PlayerInfo[id][PI_SerpentCount], 0 )
		GameInfo[GI_SerpentCount] = max( --GameInfo[GI_SerpentCount], 0 )

		if( PlayerInfo[id][PI_SerpentCount] == 0 )
			PlayerInfo[id][PI_KillAllWards] = false

		return
	}

	new iSkillLevel = SM_GetSkillLevel( id, ABILITY_SERPENTWARD )
	new iMaxNumWards = floatround(float(iSkillLevel) / 2.0, floatround_ceil)
	if( PlayerInfo[id][PI_SerpentCount] > iMaxNumWards )
	{
		PlayerInfo[id][PI_SerpentCount] = max( --PlayerInfo[id][PI_SerpentCount], 0 )
		GameInfo[GI_SerpentCount] = max( --GameInfo[GI_SerpentCount], 0 )
		return
	}

	vStart[0] = param[3]
	vStart[1] = param[4]
	vStart[2] = param[5]
	vEnd[0] = param[6]
	vEnd[1] = param[7]
	vEnd[2] = param[8]

	if( GameInfo[GI_BombPlanted] == true )
	{
		static Float:vPos[3], Float:vBombPos[3]

		vPos[0] = float( vStart[0] )
		vPos[1] = float( vStart[1] )
		vPos[2] = float( vStart[2] )

		vBombPos[0] = GameInfo[GI_BombOrigin+S_GAMEINFO:0]
		vBombPos[1] = GameInfo[GI_BombOrigin+S_GAMEINFO:1]
		vBombPos[2] = GameInfo[GI_BombOrigin+S_GAMEINFO:2]

		if( get_distance_f( vPos, vBombPos ) < 250.0 )
		{
			PlayerInfo[id][PI_SerpentCount] = max( --PlayerInfo[id][PI_SerpentCount], 0 )
			GameInfo[GI_SerpentCount] = max( --GameInfo[GI_SerpentCount], 0 )

			client_print( id, print_chat, "%s Serpent ward removed, you can't have them near bombs or hostages!", g_MODclient )
			return
		}

	}
	
	// Draw the serpent ward
	if( GameInfo[GI_SerpentCount] <= 9 )
	{
		Create_TE_BEAMPOINTS( vStart, vEnd, g_spr_lgtning, random_num(1,10), 18, 5, 255, 25, color, 13 )
		Create_TE_BEAMPOINTS( vEnd, vStart, g_spr_lgtning, random_num(1,10), 13, 5, 255, 25, color, 10 )
	}
	else
	{
		Create_TE_BEAMPOINTS( vStart, vEnd, g_spr_lgtning, random_num(1,10), 13, 5, 255, 25, color, 100 )
	}

	// Now lets check and see if any enemy players are near that need to be damaged
	static vTargetOrigin[3]

	new iTargetTeam = (team == TEAM_CT) ? TEAM_T : TEAM_CT

	new iDamage = p_serpent[iSkillLevel-1]

	new iTargetID

	// Loop through all players and see if anyone nearby needs to be damaged
	for( new i = 0 ; i < g_NumTeamPlayers[iTargetTeam] ; i++ )
	{
		iTargetID = g_SortedTeams[iTargetTeam][i]
	
		if( !is_user_alive(iTargetID) )
			continue
			
		get_user_origin( iTargetID, vTargetOrigin )

		if( vTargetOrigin[2] < vStart[2] || vTargetOrigin[2] > vEnd[2] )
			continue

		vTargetOrigin[2] = vStart[2]
		if( get_distance( vStart, vTargetOrigin ) > 100 )
			continue
		
		// Damage the user
		PLAYER_MagicDamage( iTargetID, id, iDamage, CSW_SERPENTWARD )

		// Make the sound when they're attacked
//		client_cmd( iTargetID, "speak ambience/thunder_clap.wav" )
		client_cmd( id, "speak houndeye/he_hunt3.wav" )

		// Create screen fade on the owners screen
		EFFECT_ScreenFade( id, 0.25, 0.25, color & ~255 | 60 )

		// Create screen fade on the victims screen
		EFFECT_ScreenFade( iTargetID, 0.25, 1.0, color & ~255 | 255 )
	}

	set_task( 0.5, "_HUNTER_DrawSerpentWard", TASK_DELAYEDFUNCTION, param, 9 )
}


//------------------------------------
// HUNTER_CanPlaceWard
//
//------------------------------------
bool:HUNTER_CanPlaceWard( id )
{
	new vPlayerOrigin[3]
	get_user_origin( id, vPlayerOrigin )

	// Make sure the user isn't trying to place a ward near a hostage
	if ( SHARED_NearObjective( vPlayerOrigin ) == OBJENT_HOSTAGE )
		return false

	// Make sure the user isn't trying to place a ward near the bomb
	new iEnt, fOrigin[3]
	pev( id, pev_origin, fOrigin )
	while( ( iEnt = fm_find_ent_in_sphere( iEnt, fOrigin, 250.0 ) ) )
	{
		pev( iEnt, pev_classname, szTmpMsg, 31 )
		if( equali( szTmpMsg, "grenade" ) )
		{
			pev( iEnt, pev_model, szTmpMsg, 31 )
			if( equali( szTmpMsg, "models/w_c4.mdl" ) )
				return false
		}
	}
	return true
}


//--------------------------------------------------------------------------------------------------------------------------
// The Beast Within

#define BEASTWITHIN_DURATION	10.0

//------------------------------------
// _SPELL_BeastWithin
//
// PLAYER_CastSpell callback
//		param[0] = Caster ID
//------------------------------------
public _SPELL_BeastWithin( const param[] )
{
	new id = param[0]

	if( !is_user_alive(id) )
		return

	PlayerInfo[id][PI_CanRender] = false
	PlayerBuffInfo[id][BUFF_BeastWithin] = true

	emit_sound( id, CHAN_STATIC, g_szSounds[SOUND_BLOODLUST], VOL_NORM, ATTN_NORM, 0, PITCH_NORM )

	ULT_Icon( id, ICON_FLASH )

	fm_set_user_rendering( id, kRenderFxGlowShell, 255, 64, 0, kRenderNormal, 18 )

	EFFECT_EntityLight( id, _, _, COLOR_RGB(255,164,128), BEASTWITHIN_DURATION )

	set_task( BEASTWITHIN_DURATION, "_SPELL_RemoveBeastWithin", TASK_ALIVE_EFFECT + id )
}


//------------------------------------
// _SPELL_RemoveBeastWithin
//
//------------------------------------
public _SPELL_RemoveBeastWithin( id )
{
	id = GetTaskID( id, TASK_ALIVE_EFFECT )

	if( !is_user_connected(id) )
		return

	SM_SetCooldown( id, ULTIMATE_BEASTWITHIN )

	PlayerInfo[id][PI_CanRender] = true
	PlayerBuffInfo[id][BUFF_BeastWithin] = false

	ULT_ClearIcons( id )

	PLAYER_UpdateInvisibility( id )
}
